home *** CD-ROM | disk | FTP | other *** search
- NAME msssen
- ; File MSSSEN.ASM
- include mssdef.h
-
- ; Copyright (C) 1985, 1993, Trustees of Columbia University in the
- ; City of New York. Permission is granted to any individual or institution
- ; to use this software as long as it is not sold for profit. This copyright
- ; notice must be retained. This software may not be included in commercial
- ; products without written permission of Columbia University.
- ;
- ; Edit history:
- ; 27 August 1992 version 3.13
- ; 6 Sept 1991 version 3.11
- ; Last edit 15 May 1993
- ; Sliding Windows
-
- public spar, rpar, nout, send, flags, trans, dtrans, packlen
- public send10, mail, newfn, errpack, sstate, response, ackmsg
- public pktnum, numpkt, cntretry, sndpak, sparmax, remprn
-
- spmin equ 20 ; Minimum packet size
- spmax equ 94 ; Maximum packet size
-
- data segment
- extrn fsta:word, auxfile:byte, encbuf:byte, decbuf:byte, maxtry:byte
- extrn errlev:byte, kstatus:word, diskio:byte, rpacket:byte
- extrn windflag:byte, rstate:byte, fmtdsp:byte, windlow:byte
- extrn charids:word, portval:word, chkparflg:byte, maxbufparas:word
- extrn protlist:byte, flowon:byte, flowoff:byte
-
- flags flginfo <>
- trans trinfo <> ; negotiated trans information
- dtrans trinfo <> ; default trans information
- crlf db cr,lf,'$'
- ender db bell,bell,'$'
- cemsg db 'User intervention',0
- erms14 db 'No response from the host',0
- erms15 db 'File not found',0
- erms17 db 'Too many retries',0
- erms24 db 'Unable to send packet',0
- erms25 db 'Host does not support Kermit MAIL command',0
- erms26 db 'File rejected by host',0
- erms27 db 'Error. No buffers in send routine',0
- erms30 db ': File size',0
- erms31 db ': Date/time',0
- erms32 db ': Mailing refused',0
- erms33 db ': File Type',0
- erms34 db ': Transfer Char-set',0
- erms36 db ': Unknown reason',0
- infms1 db cr,' Sending: In progress',cr,lf,'$'
- infms2 db cr,' Mailing: In progress',cr,lf,'$'
- infms3 db 'Completed',cr,lf,'$'
- infms4 db 'Failed',cr,lf,'$'
- infms5 db 'Remote name is ',0
- filhlp db ' A filename (possibly wild)$'
- filmsg db ' Local Source File or press ENTER for prompts$'
- remfnm db ' Remote Destination File: ',0 ; asciiz
- lclfnm db ' Local Source File: ',0 ; asciiz
- mailhlp db ' Filename mail-address or press ENTER for prompts$'
- mailto db ' To: ',0 ; asciiz
- mailtohlp db ' mail address (eg, user@host or host::user)$'
- mailflg db 0 ; 1 if Mail, 0 if Send command
- printhlp db ' Filename and any extra host''s printer paramters$'
- printpmt db ' Host printer parameters: ',0 ; asciiz
- printas db ' host''s printer parameters, such as /COPIES=2/QUE=HPLJ$'
- asmsg db ' as ',0
- sstate db 0 ; current automata state
- pktnum db 0 ; packet number
- sndcnt db 0 ; retry counter for sndpak, internal
- filopn db 0 ; 1 if disk file is open for reading
- tempseq db 0 ; target sequence number for responses
- retry db 0 ; current retry threshold
- even
- current_max dw 40 ; current max D packet length
- attlist dw sat5t,sat1t,sat2t,sat3t,sat4t,sat6t,sat7t,0 ;attrib procedures
- attptr dw 0 ; pointer to items in attlist
- numpkt dw 0 ; number of packets for file group
- temp dw 0
- temp4 dw 0
- ninefive dw 95 ; constant word for long packets
- data ends
-
- code1 segment
- extrn bufclr:far, pakptr:far, bufrel:far, makebuf:far, chkwind:far
- extrn getbuf:far, rpack:far, spack:far, fcsrtype:far, peekreply:far
- code1 ends
-
- code segment
- extrn serini:near, comnd:near, init:near
- extrn gtnfil:near, gtchr:near, clrbuf:near, filekind:near
- extrn getfil:near, rprpos:near, prtasz:near, cxerr:near
- extrn ermsg:near, rtmsg:near, cxmsg:near, stpos:near, decout:near
- extrn doenc:near, dodec:near, lnout:near, winpr:near
- extrn prompt:near, intmsg:near, msgmsg:near
- extrn strcpy:near, strlen:near, pktsize:near, isfile:near
- extrn pcwait:near, ihostr:near, begtim:near, endtim:near, filecps:near
-
- assume cs:code, ds:data, es:nothing
-
- ; Data structures comments.
- ; Sent raw text material (typically rpar and filenames) is placed in encbuf,
- ; which may be encoded by doenc. doenc needs an output buffer provided as
- ; a pointer generated here via procedure buflist. encbuf is 512 bytes long.
- ; Sent packet material is placed in buffers pointed at by buflist. These
- ; buffers are subdivisions of one large buffer bufbuf (private to msscom).
- ; Proceedure makebuf does the subdivision and initialization of contents.
- ; Received material is directed to buffer rbuf which is part of structure
- ; rpacket; rbuf is 128 bytes long.
- ; Rpack and Spack expect a pointer in SI to the packet data field, done in a
- ; pktinfo format.
-
- ; SEND filespec
- ; MAIL filspec user@node
- ; REMOTE PRINT filespec parameters
-
- SEND PROC NEAR
- mov mailflg,0 ; Send command, not Mail command
- mov temp,0
- jmp short send1 ; join common code
-
- MAIL: mov mailflg,1 ; set flag for Mail command vs Send
- mov temp,1 ; temp copy of mailflag
- jmp short send1
-
- REMPRN: mov mailflg,2 ; REMOTE PRINT entry point
- mov temp,2
-
- send1: mov auxfile,0 ; clear send-as name (in case none)
- mov dx,offset diskio.string ; address of filename string
- mov bx,offset filmsg ; help message
- cmp mailflg,0 ; Mail command?
- je send2 ; e = no
- mov mailflg,0 ; clear in case error exit
- mov bx,offset mailhlp ; help message
- cmp temp,2 ; REMOTE PRINT?
- jne send2 ; ne = no
- mov bx,offset printhlp ; help message
- send2: mov ah,cmword ; get input file spec
- call comnd
- jnc send2a ; nc = success
- ret ; failure
- send2a: cmp diskio.string,'#' ; first char a replacement for '?'?
- jne send2b ; ne = no
- mov diskio.string,'?' ; yes. Change '#' for '?'
- send2b: or ax,ax ; any text given?
- jz send3 ; z = no, prompt
- cmp temp,0 ; Mail or REMOTE PRINT command?
- jne send5 ; ne = yes, require address etc
- mov bx,offset auxfile ; send file under different name?
- mov dx,offset filhlp ; help
- mov ah,cmline ; allow embedded white space
- call comnd
- jnc send2c ; nc = success
- ret ; failure
- send2c: cmp auxfile,'#' ; first char a replacement for '?'?
- jne send2d ; ne = no
- mov auxfile,'?' ; change '#' to '?'
- send2d: jmp send6 ; join common completion code
-
- send3: mov dx,offset lclfnm ; prompt for local filename
- call prompt
- mov dx,offset diskio.string ; reload destination of user's text
- mov bx,offset filhlp ; help
- mov ah,cmword ; get filename
- call comnd ; try again for a local filename
- jnc send3a ; nc = success
- ret ; failure
- send3a: cmp diskio.string,'#' ; first char a replacement for '?'?
- jne send3b ; ne = no
- mov diskio.string,'?' ; yes. Change '#' for '?'
- send3b: push ax
- mov ah,cmeol ; get the terminating CR
- call comnd
- pop ax
- jnc send3c ; nc = success
- ret ; failure
- send3c: or ax,ax ; user's byte count
- jz send3 ; z = nothing was typed, get some
-
- send4: mov dx,offset remfnm ; ask for remote name first
- cmp temp,0 ; Mail command?
- je send4a ; e = no
- mov dx,offset mailto ; ask for name@host
- cmp temp,2 ; REMOTE PRINT?
- jne send4a ; ne = no
- mov dx,offset printpmt ; ask for host print parameters
- send4a: call prompt
- send5: mov bx,offset auxfile ; send file under different name?
- mov dx,offset filhlp ; help
- cmp temp,0 ; Mail command?
- je send5a ; e = no
- mov dx,offset mailtohlp ; help
- cmp temp,2 ; REMOTE PRINT?
- jne send5a ; ne = no
- mov dx,offset printas ; help for printer parameters
- send5a: mov ah,cmline ; allow embedded white space
- call comnd
- jnc send5b ; nc = success
- ret ; failure
- send5b: cmp temp,2 ; REM Print cmd?
- je send6 ; e = yes, allow no parameters
- or ax,ax ; text entered?
- jz send4 ; z = no, get some
-
- send6: mov flags.xflg,0 ; reset flag for normal file send[mtd]
- mov sstate,0 ; dummy state, must be illegal
- mov ax,temp ; get temp mailflag
- mov mailflg,al ; store in secure area for later
- mov ah,trans.sdelay ; seconds to delay before sending
- shl ah,1 ; times 4*256 to get millisec
- shl ah,1 ; for pcwait
- mov al,1 ; set low byte to 1 for no delay case
- call pcwait ; wait number of millisec in ax
- SEND10: ; SEND10 is an entry point for REMote cmds
- mov kstatus,kssuc ; global status, success
- mov windflag,0 ; init windows in use display flag
- mov trans.windo,1 ; one window slot before negotiations
- mov cx,dspsiz ; default send pkt length (94)
- call makebuf ; make some packet buffers
- call clrbuf ; clear port buffer of old NAKs
- call packlen ; compute packet length
- call cxerr ; clear Last Error line
- call cxmsg ; clear Last Message line
- mov ax,offset diskio.string ; filename to send, can be wild
- call isfile ; does file exist?
- jnc send12 ; carry reset = yes, file found
- cmp sstate,'S' ; was this from a remote GET?
- jne send11 ; ne = no, print error and continue
- mov dx,offset erms15 ; file not found
- mov trans.chklen,1 ; send init checksum is always 1 char
- call ermsg
- mov bx,dx
- call errpack ; go complain
- mov sstate,'A' ; abort
- ret
-
- send11: mov ah,prstr
- mov dx,offset crlf
- int dos
- mov dx,offset erms15 ; 'file not found'
- call prtasz
- or errlev,kssend ; set DOS error level
- or fsta.xstatus,kssend ; set status
- mov kstatus,kssend ; global status
- mov mailflg,0 ; clear Mail flag
- clc ; pretend successful completion
- ret
-
- send12: call serini ; initialize serial port
- jnc send13 ; nc = success
- or errlev,kssend ; say send failed
- or fsta.xstatus,kssend ; set status
- mov kstatus,kssend ; global status
- mov dx,offset erms14 ; no response from host
- call ermsg ; show message
- stc ; return failure
- ret
-
- send13: xor ax,ax
- mov pktnum,al ; set the packet number to zero
- mov fsta.pretry,ax ; set the number of retries to zero
- mov numpkt,ax ; number pkts send in this file group
- mov flags.cxzflg,al
- mov sstate,'S' ; set the state to send initiate
- mov chkparflg,1 ; check for unexpected parity
- call ihostr ; initialize the host (clear NAKs)
- call init ; clear screen and initialize buffers
- call clrbuf ; clear serial port buffer of junk
- test flags.remflg,dquiet+dserial ; quiet or serial display mode?
- jnz send15 ; nz = yes, suppress msgs
- call stpos ; show status of file transfer
- mov dx,offset infms1 ; Sending in progress message
- cmp mailflg,0 ; Sending, vs Mailing?
- je send14 ; e = yes, sending
- mov dx,offset infms2 ; Mailing in progress message
- send14: mov ah,prstr
- int dos
- send15: jmp short dispatch ; sstate has initial state ('S')
- SEND ENDP
-
- dispatch proc near ; Dispatch on state variable sstate
- mov ah,sstate
- cmp ah,'S' ; send initiate state?
- jne dispat2 ; ne = no
- call sinit ; negotiate
- jmp short dispatch
-
- dispat2:cmp ah,'F' ; file header state?
- jne dispat3 ; ne = no
- call sfile ; send file header
- jmp short dispatch
-
- dispat3:cmp ah,'a' ; send attributes state?
- jne dispat4 ; ne = no
- call sattr ; send attributes
- jmp short dispatch
-
- dispat4:cmp ah,'D' ; data send state?
- jne dispat5 ; ne = no
- call sdata ; send data
- jmp short dispatch
-
- dispat5:cmp ah,'Z' ; EOF state?
- jne dispat6
- call seof ; do EOF processing
- jmp short dispatch
-
- dispat6:cmp ah,'B' ; end of file group state?
- jne dispat7
- call seot
- jmp short dispatch
-
- dispat7:cmp ah,'E' ; user intervention ^C or ^E?
- jne dispat8 ; ne = no
- mov bx,offset cemsg ; user intervention message
- call errpack ; send error message
- call intmsg ; show interrupt msg for Control-C-E
-
- dispat8:push ax ; 'A' abort or 'C' completion
- pop ax
- mov mailflg,0 ; clear Mail flag
- call bufclr ; release all buffers
- mov windlow,0
- mov pktnum,0
- call stpos ; show status of file transfer
- mov dx,offset infms3 ; Completed message
- cmp sstate,'C' ; send complete state?
- je dispat9 ; e = yes, else failure
- mov dx,offset infms4 ; Failed message
- or errlev,kssend ; say send failed
- or fsta.xstatus,kssend ; set status
- mov kstatus,kssend ; global status
-
- dispat9:test flags.remflg,dquiet+dserial ; quiet or serial display mode?
- jnz dispa9a ; nz = yes, keep going
- mov ah,prstr ; show completed/failed message
- int dos
- mov al,1 ; underline cursor
- call fcsrtype ; set IBM-PC cursor to underline
- dispa9a:cmp flags.cxzflg,0 ; completed normally?
- je dispa10 ; e = yes
- or errlev,kssend ; say send failed
- or fsta.xstatus,kssend+ksuser ; set status, failed + intervention
- mov kstatus,kssend+ksuser ; global status
- dispa10:mov ax,1 ; tell statistics this was a send operation
- call endtim ; stop statistics counter
- test flags.remflg,dquiet ; quiet display mode?
- jnz dispa13 ; nz = yes, no talking
- call filecps ; show file chars/sec
- call intmsg ; show any interruption
- cmp flags.belflg,0 ; Bell desired?
- je dispa13 ; e = no
- mov ah,prstr
- mov dx,offset ender ; ring bells
- int dos
- dispa13:call rprpos ; position cursor
- xor al,al
- mov flags.cxzflg,al ; clear flag for next command
- mov auxfile,al ; clear send-as filename buffer
- mov flags.xflg,al ; clear to-screen flag
- mov diskio.string,al ; clear active filename buffer
- mov fsta.xname,al ; clear statistics external name
- clc
- ret ; return to main command parser
- dispatch endp
-
- ; Enter with filespec in diskio.string, external name/mail address in auxfile
-
- ; Send Initiate packet
- SINIT PROC NEAR
- mov al,1 ; say starting send operation
- mov trans.windo,1 ; one window slot before negotiations
- mov cx,dspsiz ; default send pkt length (94)
- call makebuf ; remake buffers for new windowing
- call packlen ; compute packet length
- xor ax,ax
- mov windlow,al ; window lower border
- mov pktnum,al ; sequence number to use
- mov windflag,al ; windows in use display flag
- mov al,dtrans.xchset ; reset Transmission char set
- mov trans.xchset,al ; to the current user default
- mov al,dtrans.xtype ; ditto for File Type
- mov trans.xtype,al
- call getbuf ; get a buffer address into si
- call sparmax ; set up our maximum capabilities
- call rpar ; put them into the packet
- mov trans.chklen,1 ; Send init checksum is always 1 char
- mov [si].pktype,'S' ; send-initiate packet
- call sndpak ; send the packet
- jnc sinit2 ; nc = successful send
- ret ; failure, change state
-
- sinit2: mov al,pktnum ; packet just sent
- mov ah,maxtry ; normal retry threshold
- add ah,ah
- add ah,maxtry ; triple the normal threshold
- call response ; get response
- jnc sinit3 ; nc = success
- ret
-
- sinit3: push si ; ACK in window
- mov si,offset rpacket ; point to packet for spar
- call spar ; parse the received data
- pop si
- mov cx,trans.slong ; negotiated send packet size
- call makebuf ; remake buffers for new windowing
- call packlen ; update max send packet size
- mov pktnum,1 ; next sequence number after 'S' pkts
- mov windlow,1 ; lowest acceptable sequence received
- cmp mailflg,0 ; non-zero to do Mail command
- je sinit4 ; e = send, not mail command
- cmp flags.attflg,0 ; file attributes disabled?
- je sinit5 ; e = yes, so no Mail
- test trans.capas,8 ; can they do file attributes?
- jz sinit5 ; z = no, so cannot do Mail
- sinit4: call getfil ; open the file
- jc sinit4a ; c = error
- mov filopn,1 ; disk file is open
- mov sstate,'F' ; set the state to file send
- ret
-
- sinit4a:mov dx,offset erms15 ; file not found
- jmp giveup ; something is wrong, quit w/msgs
-
- ; say Mail not supported by host
- sinit5: mov dx,offset erms25 ; say no mail today
- call ermsg ; tell both sides
- mov sstate,'B' ; go to EOT state
- ret
- SINIT ENDP
-
- ; Send file header
- ; Enter with pktnum set for the next transmission, no buffer
-
- SFILE PROC NEAR
- mov al,1 ; say starting send operation
- call begtim ; start statistics
- cmp filopn,1 ; is file open already?
- je sfile1 ; e = yes
- call bufrel ; release buffer for SI
- mov dx,offset erms24 ; cannot send packet
- jmp giveup ; something is wrong, quit
-
- sfile1: mov flags.cxzflg,0 ; clear ^C, ^E, ^X, ^Z flag
- call getbuf ; get a packet buffer, address in si
- jnc sfile2 ; nc = got one
- mov dx,offset erms27 ; no buffers
- jmp giveup ; tell both sides and fail
-
- sfile2: mov dx,offset encbuf ; destination = encode source buffer
- call strlen ; get length (w/o terminator) into cx
- call doenc ; do encoding; length is in cx
- mov [si].pktype,'F' ; File header packet
- cmp flags.xflg,0 ; REMOTE command? (goes to screen)
- je sfile3 ; e = no
- mov [si].pktype,'X' ; use X rather than F for REMOTE cmds
- sfile3: call sndpak ; send the packet
- jnc sfile4 ; nc = success
- ret
-
- sfile4: mov al,pktnum ; want response for packet just sent
- mov ah,maxtry ; retry threshold
- call response ; get response
- jnc sfile5 ; nc = success (got an ACK)
- ret
-
- sfile5: call ackmsg ; show any message in ACK
- inc pktnum ; next pkt to send/rcv, from ackpak
- and pktnum,3fh ; modulo 64
- call filekind ; report file type, char set
- push trans.maxdat ; negotiated max packet length
- pop current_max ; set current D packet length
- mov sstate,'D' ; send data as the next state
- test trans.capas,8 ; can they do file attributes?
- jz sfile6 ; z = no, so cannot do attributes
- mov sstate,'a' ; set file attributes as next state
- sfile6: ret ; return to do next state
- SFILE ENDP
-
- ; Send file attributes. Attributes: file size in bytes and kilobytes,
- ; file time and date, machine identification.
- ; Writes output to buffer encbuf.
- SATTR PROC NEAR
- cmp flags.attflg,0 ; allowed to do file attributes?
- je satt0 ; e = no
- mov attptr,offset attlist ; point at list of attributes procs
- test trans.capas,8 ; can we do file attributes?
- jnz satt1 ; nz = yes
- satt0: mov sstate,'D' ; set the state to send-data
- ret
-
- satt1: mov bx,attptr ; ptr to list of attributes procedures
- cmp word ptr [bx],0 ; at end of list?
- je satt0 ; e = yes, do next state
- call getbuf ; get buffer for sending
- jnc satt2 ; nc = got one
- mov dx,offset erms27 ; no buffers
- jmp giveup ; tell both sides and fail
-
- satt2: mov di,offset encbuf ; address of a temp data buffer
- mov byte ptr [di],0 ; start with null terminator
- push es ; save es around this work
- push ds
- pop es ; set es to data segment for es:di
- push si
- mov bx,attptr ; ptr to list of attributes routines
- mov bx,[bx] ; de-reference one level
- call bx ; do it
- pop si
- pop es
- mov byte ptr [di],0 ; insert null terminator in temp buf
- mov dx,offset encbuf
- call strlen ; get length of this attribute to CX
- cmp cx,trans.maxdat ; longer than any packet?
- jbe satt3 ; be = no, proceed
- call bufrel ; release this buffer
- mov dx,offset erms24 ; "Unable to send packet"
- call ermsg ; position cursor, display asciiz msg
- mov flags.cxzflg,'X' ; say skip this file
- mov sstate,'Z' ; move to EOF state
- ret
-
- satt3: mov ax,[si].datlen ; data length for packet, so far
- add ax,cx ; plus, maybe, this contribution
- cmp ax,trans.maxdat ; new info fits into packet?
- jg satt4 ; g = no, send what we have
- push si ; preserve packet structure pointer
- push es
- les di,[si].datadr ; packet buffer beginning
- add di,[si].datlen ; plus current contents
- add [si].datlen,cx ; say adding this many bytes
- mov si,offset encbuf ; temp buffer is source of new info
- cld ; packet buffer is destination
- rep movsb ; copy new material to packet buffer
- pop es
- pop si
- add attptr,2 ; next attributes procedure address
- mov bx,attptr
- cmp word ptr [bx],0 ; at end of list?
- jne satt2 ; ne = no, do next attribute proc
- cmp [si].datlen,0 ; any data to send?
- jne satt4 ; ne = yes
- call bufrel ; release the unused buffer
- mov sstate,'D' ; set the state to send-data
- ret
-
- satt4: call sndatt ; send attributes packet, get response
- jc satt5 ; c = failure
- jmp satt1 ; get new buffer, do more attributes
- satt5: ret ; failure, change state
-
- ; Send Attributes packet, local worker
- sndatt: mov [si].pktype,'A' ; Attributes packet
- call sndpak ; send the packet
- jnc sndat1 ; nc = success
- ret
- sndat1: mov al,pktnum ; get response for packet just sent
- mov ah,maxtry ; retry threshold
- call response ; get response
- jnc sndat2 ; nc = success
- ret
-
- sndat2: inc pktnum ; sent and ack'd, next seqnum to use
- and pktnum,3fh
- cmp rpacket.datlen,0 ; any data in the ACK?
- je sndat3 ; e = no
- push es
- les bx,rpacket.datadr ; received data field
- mov al,es:[bx] ; response
- inc bx ; point to next field
- cmp al,'N' ; are they refusing this file?
- pop es
- je sndat4 ; e = yes, 'N' = refusing the file
- sndat3: clc ; say success
- ret
- ; display file refusal reason
- sndat4: test flags.remflg,dquiet ; quiet display?
- jnz sndat7 ; nz = yes
- mov dx,offset erms26 ; say host rejected the file
- call ermsg
- mov cx,rpacket.datlen ; display all reasons
- sndat5: dec cx ; next byte
- cmp cx,0 ; anything there?
- jle sndat7 ; b = no
- push es
- mov es,word ptr rpacket.datadr+2 ; received data field seg
- mov ah,es:[bx] ; reason code
- inc bx ; point to next field
- pop es
- mov dx,offset erms30 ; ah has reason code from above
- cmp ah,'1' ; Byte count?
- je sndat6 ; e = yes
- cmp ah,'!' ; Kilobyte count?
- je sndat6
- mov dx,offset erms31
- cmp ah,'#' ; Date and Time?
- je sndat6 ; e = yes
- mov dx,offset erms32
- cmp ah,'+' ; Mail?
- je sndat6 ; e = yes
- mov dx,offset erms33
- cmp ah,'"' ; File Type?
- je sndat6
- mov dx,offset erms34
- cmp ah,'*' ; Transfer Char-set?
- je sndat6
- mov dx,offset erms36 ; unknown reason
- sndat6: call prtasz ; display reason
- jmp short sndat5 ; do any other reasons
- sndat7: mov flags.cxzflg,'X' ; simulate Control-X to discard
- mov sstate,'Z' ; send EOF with Discard
- stc
- ret
-
- ; Individual attribute routines. Each expects DI to point to a free storage
- ; byte in an output buffer and it updates DI to the next free byte. Expects
- ; ES to be pointing at the data segment. OK to clobber SI here.
-
- sat1t: test flags.attflg,attlen ; can we send length attribute?
- jz sat1tx ; z = no
- mov si,di ; remember starting location
- mov byte ptr [di],'1' ; file length (Bytes) specifier
- mov dx,diskio.sizehi ; high word of length
- mov ax,diskio.sizelo ; low word of length
- add di,2
- call lnout ; convert file length, write to [di++]
- mov cx,di ; compute field length
- sub cx,si
- sub cx,2
- add cl,32 ; field length to ascii
- mov [si+1],cl ; length. Done with File Size
- sat1tx: ret
- ; Kilobyte attribute
- sat2t: test flags.attflg,attlen ; can we send length attribute?
- jz sat2tx ; z = no
- mov byte ptr[di],'!' ; file length (Kilobytes) specifier
- inc di
- mov temp4,di ; remember place for count field
- inc di ; data field
- mov dx,diskio.sizehi ; high word of length, from file open
- mov ax,diskio.sizelo ; low word of length
- add ax,1023 ; add 1023 to round up
- adc dx,0
- mov al,ah ; do divide by 1024 bytes
- mov ah,dl
- mov dl,dh ; divide by 256 part
- xor dh,dh
- ror dl,1 ; low bit to carry flag
- rcr ax,1 ; divide by two, with carry in
- clc
- ror dl,1 ; low bit to carry flag
- rcr ax,1 ; divide by two, with carry in
- and dl,3fh ; keep low six bits
- call lnout ; convert file length
- mov cx,di ; compute field length
- sub cx,temp4 ; count field location
- add cl,32-1 ; field length to ascii
- push di
- mov di,temp4 ; point at count field
- mov [di],cl ; store field length
- pop di ; Done with Kilobyte attribute
- sat2tx: ret
-
- sat3t: test flags.attflg,attdate ; can we send file date and time?
- jnz sat3t1 ; nz = yes
- ret
- sat3t1: cld ; file Date and Time
- mov al,'#' ; creation date/time specifier
- stosb ; and point at field length
- mov al,17+32 ; length of date/time field, to ascii
- stosb
- xor ah,ah
- mov al,diskio.dta+25 ; yyyyyyym from DOS via file open
- shr al,1 ; get year
- add ax,1980 ; add bias
- xor dx,dx
- call lnout ; put year (1990) in buffer
- mov ax,word ptr diskio.dta+24 ; yyyyyyyym mmmddddd year+month+day
- shr ax,1 ; month to al
- xor ah,ah
- mov cl,4
- shr al,cl ; month to low nibble
- mov byte ptr[di],'0' ; leading digit
- inc di
- cmp al,9 ; more than one digit?
- jbe sat3t2 ; be = no
- mov byte ptr[di-1],'1' ; new leading digit
- sub al,10 ; get remainder
- sat3t2: add al,'0' ; to ascii
- stosb ; end of month
- mov al,diskio.dta+24 ; get day of month
- and al,1fh ; select day bits
- xor ah,ah
- mov cl,10
- div cl ; quot = al, rem = ah
- add ax,'00' ; add ascii bias
- stosw ; leading digit and end of date
- mov al,' ' ; space separator
- stosb
- mov al,diskio.dta+23 ; hours hhhhhmmm
- mov cl,3
- shr al,cl ; move to low nibble
- xor ah,ah
- mov cl,10
- div cl ; quot = al, rem = ah
- add ax,'00' ; add ascii bias
- stosw ; store hours
- mov al,':' ; separator
- stosb
- mov ax,word ptr diskio.dta+22 ; get minutes: hhhhhmmm mmmsssss
- mov cl,5
- shr ax,cl ; minutes to low byte
- and al,3fh ; six bits for minutes
- xor ah,ah
- mov cl,10
- div cl
- add ax,'00' ; add ascii bias
- stosw
- mov al,':' ; separator
- stosb
- mov al,byte ptr diskio.dta+22 ; get seconds (double secs really)
- and al,1fh
- shl al,1 ; DOS counts by two sec increments
- xor ah,ah
- mov cl,10
- div cl
- add ax,'00' ; add ascii bias
- stosw
- ret
-
- sat4t: mov ax,'".' ; machine indicator(.), 2 data bytes
- cld
- stosw
- mov ax,'8U' ; U8 = Portable O/S, MSDOS
- stosw
- ret
-
-
- sat5t: cmp mailflg,0 ; Mailing or REMOTE PRINTing?
- jne sat5t1 ; ne = yes
- ret
- sat5t1: mov byte ptr [di],'+' ; Disposition specification
- inc di
- mov dx,offset auxfile ; user@host or print param field
- call strlen ; get length into cl
- push cx ; save address length
- inc cl ; include disposition letter M or P
- add cl,' ' ; add ascii bias
- mov [di],cl ; store in length field
- inc di
- mov byte ptr [di],'M' ; mail the file
- cmp mailflg,2 ; REMOTE PRINT?
- jne sat5t2 ; ne = no
- mov byte ptr [di],'P' ; say disposition is Print
- sat5t2: inc di
- pop cx ; recover address length
- jcxz sat5tx ; z = empty field
- mov si,dx ; parameter field
- cld
- rep movsb ; append address text to field
- sat5tx: ret
-
- sat6t: test flags.attflg,atttype ; can we send File Type attribute?
- jz sat6tx ; z = no
- mov al,'"' ; File Type attribute (")
- cld
- stosb
- cmp dtrans.xtype,0 ; Text?
- jne sat6t1 ; ne = no, likely Binary
- mov al,3+20h ; three bytes follow
- stosb
- mov al,'A' ; A for ascii
- stosb
- mov ax,'JM' ; using Control-M and Control-J
- stosw ; as line delimiters
- ret
- sat6t1: mov al,2+20h ; two bytes follow
- stosb
- mov ax,'8B' ; "B8" = Binary, 8-bit byte literals
- stosw
- sat6tx: ret
-
- sat7t: test flags.attflg,attchr ; Character-set allowed?
- jz sat7tx ; z = no
- cmp dtrans.xtype,1 ; Binary?
- je sat7tx ; e = yes, no char-set stuff
- mov al,'*' ; Encoding strategy
- cld
- stosb
- mov al,1+20h ; length following, say one char
- stosb
- mov al,'A' ; assume normal Transparent
- stosb
- cmp dtrans.xchset,xfr_xparent ; is it transparent?
- je sat7tx ; e = yes
- mov al,'C' ; say transfer char-set encoding
- dec di ; replace 'A' with 'C'
- stosb
- push bx
- mov bl,dtrans.xchset ; get def char set index
- xor bh,bh
- shl bx,1 ; count words
- mov bx,charids[bx+2] ; bx points at set [length, string]
- mov al,[bx] ; get length of ident string
- mov cl,al ; copy to loop counter
- xor ch,ch
- inc al ; add 'C' in attribute
- add al,20h ; length of string + ascii bias
- mov byte ptr [di-2],al ; length of attribute
- push si
- mov si,bx ; ident string length byte
- inc si ; text of ident string
- cld
- rep movsb ; copy to destination
- pop si
- pop bx
- sat7tx: ret
-
- SATTR ENDP
-
- ; Send data
- ; Send main body of file, 'D' state
-
- SDATA PROC NEAR
- cmp flags.cxzflg,0 ; interrupted?
- je sdata1 ; e = no
- mov sstate,'Z' ; declare EOF, analyze interrupt there
- ret
-
- sdata1:
- ;sdata2a:call peekresponse ; look for responses between pkts
- ; jnc sdata2a ; nc = got a response, get another
- call getbuf ; get a buffer for sending
- jnc sdata2 ; nc = success
- mov al,windlow ; earliest sequence number sent
- mov ah,maxtry ; retry threshold
- jmp response ; can't send, try getting responses
-
- sdata2: mov [si].pktype,'D' ; send Data packet
- push trans.maxdat ; negotiated max packet length
- mov ax,current_max ; running max
- mov trans.maxdat,ax ; for encoder
- call gtchr ; fill buffer from file and encode
- pop trans.maxdat ; recover negotiated max pkt
- jc sdata3 ; c = failure (no data/EOF, other)
- cmp [si].datlen,0 ; read any data?
- je sdata3 ; e = end of data, send 'Z' for EOF
- call sndpak ; send the packet
- inc pktnum ; next sequence number to send
- and pktnum,3fh ; modulo 64
- sdata2a:call peekresponse ; look for responses between pkts
- jnc sdata2a ; nc = got a response, get another
- clc ; return successful
- ret
-
- sdata3: call bufrel ; release unused buffer
- mov sstate,'Z' ; at End of File, change to EOF state
- ret
- SDATA ENDP
-
- ; Send EOF, 'Z' state
- SEOF PROC NEAR
- call getbuf ; get a buffer for EOF packet
- jnc seof1 ; nc = got one, send 'Z' packet
- mov al,pktnum ; seqnum of next packet to be used
- dec al ; back up to last used
- and al,3fh ; sequence number of last sent pkt
- mov ah,maxtry ; retry threshold
- jmp response ; get responses to earlier packets
-
- seof1: xor cx,cx ; assume no data
- cmp flags.cxzflg,0 ; interrupted?
- je seof3 ; e = no, send normal EOF packet
- call intmsg ; say interrupted
- mov encbuf,'D' ; Use "D" for discard
- mov cx,1 ; set data size to 1
- or errlev,kssend ; say send failed
- or fsta.xstatus,kssend+ksuser ; set status, failed + intervention
- mov kstatus,kssend+ksuser ; global status
- seof3: call doenc ; encode the packet (cx = count)
- mov [si].pktype,'Z' ; EOF packet
- call sndpak ; send the packet
- jnc seof6 ; nc = success
- ret
-
- seof6: mov al,[si].seqnum ; packet just sent
- mov ah,maxtry ; retry threshold
- call response ; get reponse
- jnc seof7 ; nc = success
- ret
-
- seof7: call ackmsg ; ACK, get/show any embedded message
- inc pktnum ; next sequence number to send
- and pktnum,3fh ; modulo 64
- ; Heuristic: ACK to 'Z' implies
- mov al,windlow ; ACKs to all previous packets
- mov ah,pktnum ; loop limit, next packet
- seof8: cmp al,ah ; done all "previous" packets?
- je seof8b ; e = yes
- call pakptr ; access packet for seqnum in AL
- jc seof8a ; c = not in use
- mov si,bx ; point to it
- call bufrel ; release old buffer (synthetic ACK)
- seof8a: inc al ; next slot
- and al,3fh
- jmp short seof8
- seof8b: ; end of Heuristic
- mov al,pktnum
- mov windlow,al ; update windlow to next use
- mov ah,close2 ; close file
- mov bx,diskio.handle ; file handle
- int dos
- mov filopn,0 ; no files open
- cmp flags.cxzflg,0 ; interrupted?
- je seof9 ; e = no
- or errlev,kssend ; say send failed
- or fsta.xstatus,kssend+ksuser ; set status, failed + intervention
- mov kstatus,kssend+ksuser ; global status
- cmp flags.cxzflg,'Z' ; Control-Z seen?
- jne seof9 ; ne = no
- mov ax,1 ; tell statistics this was a send
- call endtim
- mov flags.cxzflg,0 ; clear the Control-Z
- mov auxfile,0 ; clear send-as/mail-address buffer
- mov sstate,'B' ; file group complete state
- ret
- seof9: cmp flags.cxzflg,0 ; interrupted?
- je seof10 ; e = no
- cmp flags.cxzflg,'X' ; was Control-X signaled?
- je seof10 ; e = yes
- mov sstate,'E' ; not ^X/^Z, must be ^C/^E
- ret
- seof10: mov flags.cxzflg,0 ; clear the Control-X
- cmp mailflg,0 ; mail?
- jne seof11 ; e = yes, retain address in auxfile
- mov auxfile,0 ; clear send-as name
- seof11: call GTNFIL ; get the next file
- jc seof12 ; c = no more files, do end of group
- mov filopn,1 ; file opened by gtnfil
- mov sstate,'F' ; set state to file header send
- ret
- seof12: mov sstate,'B' ; set state to file group completed
- ret
- SEOF ENDP
-
-
- ; Send EOT
-
- SEOT PROC NEAR
- call getbuf ; get a buffer for sending
- jnc seot1 ; nc = got one
- mov al,pktnum ; next sequence number to use
- dec al ; back up to last used
- and al,3fh ; get response to what was just sent
- mov ah,maxtry ; retry threshold
- jmp response ; get response, stay in this state
-
- seot1: mov [si].pktype,'B' ; End of Session packet
- call sndpak ; send the packet
- jnc seot2 ; nc = sucess
- ret
- seot2: mov al,pktnum ; sequence number just sent
- mov ah,maxtry ; retry threshold
- call response ; get a response to it
- jnc seot3 ; nc = success
- ret
- seot3: call ackmsg ; get/show any embedded message
- inc pktnum ; next sequence number to use
- and pktnum,3fh ; modulo 64
- mov sstate,'C' ; set state to file completed
- ret
- SEOT ENDP
-
- ; Look for a returned response, but don't block on packet reader timeouts
- ; while waiting for a packet to start. Either reads and processes the packet
- ; or changes state on quit signal or does nothing. Returns carry set if
- ; no packet or error state, else returns what "response" does.
- peekresponse proc near
- push si ; preserve regular packet pointer
- mov si,offset rpacket ; address of receive packet structure
- call peekreply ; see if there is a reply
- pop si
- jc peekres1 ; c = no packet
- mov tempseq,-1 ; target sequence number, -1=any
- mov al,maxtry ; retry threshold
- mov retry,al
- jmp resp4 ; nc = have packet, go analyze
-
- peekres1:cmp flags.cxzflg,'C' ; Control-C typed?
- je peekres2 ; e = yes, quit
- cmp flags.cxzflg,'E' ; Control-E typed?
- jne peekres3 ; ne = no
- peekres2:mov sstate,'E' ; change to Error state
- peekres3:stc ; return saying no packet
- ret
- peekresponse endp
-
- ; Get response to seqnum in AL, retry AH times if necessary.
- ; Success: return carry clear and response data in rpacket
- ; Failure: return carry set and new state in sstate, will send Error packet
- ; Changes AX, BX, CX
- response proc near
- mov tempseq,al ; target sequence number
- mov retry,ah ; retry threshold
- mov rpacket.numtry,0 ; no receive retries yet
- resp1: mov ah,rpacket.numtry ; number of attempts in this routine
- cmp ah,retry ; done enough?
- ja resp3 ; yes, feign a timeout
- push si ; preserve regular packet pointer
- mov si,offset rpacket ; address of receive packet structure
- call rpack ; get a packet
- pop si
- jnc resp4 ; nc = success
- cmp flags.cxzflg,'C' ; Control-C typed?
- je resp2 ; e = yes, quit
- cmp flags.cxzflg,'E' ; Control-E typed?
- jne resp3 ; ne = no
- resp2: mov sstate,'E' ; change to Error state
- stc ; return failure
- ret
-
- resp3: cmp tempseq,-1 ; just shopping (accept any, no retry)?
- jne resp3e ; ne = no
- stc ; say failed to receive, don't retry
- ret
- resp3e: inc rpacket.numtry ; no packet received, resend oldest
- call shrink ; shrink new packet size
- mov al,windlow ; get oldest sequence number
- resp3a: call pakptr ; get packet pointer to seqnum in AL
- jnc resp3b ; nc = ok, sequence number is in use
- clc ; packet not in use, simulate success
- ret
-
- resp3b: push si ; resend oldest packet
- dec numpkt ; a retry is not a new packet sent
- mov si,bx ; packet pointer, from pakptr
- call cntretry ; count retries, sense ^C/^E
- jnc resp3c ; nc = ok to continue
- pop si ; clean stack
- ret ; ^C/^E encountered, change states
-
- resp3c: mov al,[si].numtry ; times this packet was retried
- cmp al,retry ; reached the limit?
- jbe resp3d ; be = no, can do more sends
- pop si ; clean stack
- mov dx,offset erms17 ; to many retries
- jmp giveup ; abort with msgs to local and remote
-
- resp3d: mov rpacket.numtry,0
- call sndpak ; resend the packet
- pop si ; clean stack
- jnc resp1 ; nc = success, retry getting response
- ret
- ; this point is also called by peekresponse
- RESP4: call acknak ; got packet, get kind of response
- or al,al ; ACK in window?
- jz resp8 ; z = yes
- cmp al,1 ; NAK in window?
- je resp6 ; e = yes, repeat pkt
- cmp al,3 ; NAK out of window?
- je resp5 ; e = yes, repeat packet
- cmp al,4 ; ACK to inactive packet?
- jne resp4e ; ne = no
- ;;
- jmp resp1 ; old ACK, ignore it
- ; the above is to accomodate "book Kermits", not a good strategy, but...
- ;; inc rpacket.numtry ; count tries on reception
- ;; jmp resp1 ; e = yes, retry reception
- resp4e: cmp al,5 ; NAK to inactive packet?
- jne resp4a ; ne = no, leaves "other" types
- jmp resp1 ; ignore NAK, try again
- ; other packet types
- resp4a: cmp rpacket.pktype,'M' ; Message packet?
- jne resp4b ; ne = no
- push si
- mov si,offset rpacket
- call msgmsg ; display it and discard
- pop si
- jmp resp1 ; retry getting an ACK
-
- resp4b: cmp rpacket.pktype,'E' ; Error packet?
- jne resp4c ; ne = no
- jmp error
-
- resp4c: jmp resp1 ; Unknown packet type, ignore it
-
- resp5: cmp trans.windo,1 ; is windowing off?
- je resp5a ; e = yes, use old heuristic
- call shrink ; shrink new packet size
- call nakout ; NAK rcvd outside window, resend all
- inc rpacket.numtry ; count this as an internal retry
- jmp resp1 ; get more responses
-
- resp5a: mov al,rpacket.seqnum ; NAK rcvd outside window, say NAK is
- dec al ; ACK for preceeding pkt to satisfy
- and al,3fh ; non-windowing Kermits
- mov rpacket.seqnum,al ; force seqnum to preceed this NAK
- mov rpacket.pktype,'Y' ; force packet to look like an ACK
- jmp short resp4 ; reanalyze our status
-
- resp6: mov al,rpacket.seqnum ; single sequence number being NAK'd
- inc rpacket.numtry ; count this as an internal retry
- call shrink ; shrink new packet size
- jmp resp3a ; repeat that packet
-
- ; ACK in window
- resp8: call grow ; grow new packet size
- mov al,windlow ; try to purge all ack'd packets
- call pakptr ; get buffer pointer for it into BX
- jc resp8a ; c = buffer not in use
- cmp [bx].ackdone,0 ; ack'd yet?
- je resp8a ; e = no, stop here
- mov si,bx
- call bufrel ; ack'd active buffer, release si
- inc al ; rotate window
- and al,3fh
- mov windlow,al
- jmp short resp8 ; keep purging
-
- resp8a: mov al,tempseq ; check for our desired seqnum
- mov rpacket.numtry,0
- cmp al,-1 ; do not check for match?
- je resp8b ; e = yes
- cmp al,rpacket.seqnum ; is this the desired object?
- je resp8b ; e = yes
- jmp resp1 ; no, read another response
- resp8b: clc ; return success
- ret
- response endp
-
- ; Send packet, with retries
- ; Enter with SI pointing to packet structure. Success returns carry clear.
- ; Failure, after retries, returns carry set and perhaps a new sstate.
- sndpak proc near
- inc numpkt ; number packets sent
- call pktsize ; report packet qty and size
- mov sndcnt,0 ; send retry counter, internal
- cmp [si].pktype,'I' ; do not show windows for I/S
- je sndpa3
- cmp [si].pktype,'S'
- je sndpa3
- call winpr ; show windows in use
-
- sndpa3: call spack ; send the packet
- jc sndpa4 ; nc = failure
- ret ; return success
-
- sndpa4: push ax ; failure, do several retries
- mov ax,100 ; wait 0.1 seconds
- call pcwait
- call cntretry ; show retries on screen
- inc sndcnt ; internal retry counter
- mov al,sndcnt
- cmp al,maxtry ; reached retry limit?
- pop ax
- jbe sndpa3 ; be = no, can do more retries
- mov dx,offset erms24 ; cannot send packet
- jmp giveup ; set carry, change state
- sndpak endp
-
- ; Check the packet rpacket for an ACK, NAK, or other.
- ; Returns in CX:
- ; 0 for ACK to active packet (marks buffer as ACK'd, may rotate window)
- ; 1 for NAK to active packet
- ; 2 for an unknown packet type
- ; 3 for NAK outside the window
- ; 4 for other ACKs (out of window, to inactive packet)
- ; 5 for NAKs in window to inactive packets.
- ; Timeout packet (type 'T') is regarded as a NAK out of the window.
- ; Marks pkts ACK'd but clears packets only when they rotate below the window.
- ; Uses registers AX ,BX, and CX.
- ACKNAK PROC NEAR
- mov al,rpacket.seqnum ; this packet's sequence number
- mov ah,rpacket.pktype ; and packet type
- cmp ah,'Y' ; ack packet?
- jne ackna2 ; ne = no
- call pakptr ; is it for an active buffer?
- jnc ackna1 ; nc = yes
- mov al,4 ; say ACK for inactive pkt
- clc
- ret
- ackna1: mov [bx].ackdone,1 ; say packet has been acked
- cmp al,windlow ; ok to rotate window?
- jne ackna1a ; ne = no
- inc windlow ; rotate window one slot
- and windlow,3fh
- push si ; save pointer
- mov si,bx ; packet pointer from pakptr
- call bufrel ; release buffer for SI
- pop si
- ackna1a:cmp rpacket.datlen,0 ; any data in the ACK?
- je ackna1c ; e = no
- cmp sstate,'F' ; in file header state?
- je ackna1c ; e = yes, no protocol char
- push es
- les bx,rpacket.datadr ; look for data in the ACK
- mov ah,es:[bx]
- pop es
- cmp ah,'C' ; Control-C message?
- je ackna1b ; e = yes
- cmp ah,'X' ; quit this file?
- je ackna1b ; e = yes
- cmp ah,'Z' ; quit this file group?
- jne ackna1c
- ackna1b:mov flags.cxzflg,ah ; store here
- mov sstate,'Z' ; move to end of file state
- mov rstate,'Z'
- ackna1c:xor al,al ; ack'd ok
- clc
- ret
- ; not an ACK
- ackna2: cmp ah,'N' ; NAK?
- je ackna3 ; e = yes
- cmp ah,'T' ; Timeout?
- je ackna3a ; e = yes, same as NAK out of window
- mov al,2 ; else say unknown type
- clc
- ret
-
- ackna3: inc fsta.nakrcnt ; count received NAK for statistics
- push si
- mov si,offset rpacket
- call chkwind ; check if seqnum is in window
- pop si
- jcxz ackna3b ; z = in window
- ackna3a:mov al,3 ; say NAK out of window
- clc
- ret
-
- ackna3b:push bx ; NAK in window, is pkt still active?
- call pakptr ; seqnum for an active packet?
- pop bx
- jc ackna4 ; c = no, ignore NAK as "dead NAK"
- mov al,1 ; say NAK for active packet
- clc
- ret
-
- ackna4: mov al,5 ; dead NAKs
- clc
- ret
- ACKNAK ENDP
-
- nakout proc near ; NAK out of window, resend all pkts
- mov al,windlow ; start here
- mov ah,al
- add ah,trans.windo
- and ah,3fh ; top of window+1
- nakout1:call pakptr ; get pkt pointer for seqnum in al
- jc nakout4 ; c = slot not in use
- mov si,bx ; bx is packet pointer from pakptr
- cmp [si].ackdone,0 ; has packet has been acked?
- jne nakout4 ; ne = yes
- cmp al,windlow ; count retries only for windlow
- jne nakout2 ; ne = not windlow
- call cntretry ; count retries
- jc nakout3 ; c = quit now
- mov cl,[si].numtry
- cmp cl,retry ; reached the limit yet?
- ja nakout3 ; a = yes, quit
- nakout2:push ax
- call pktsize ; report packet size
- call sndpak ; resend the packet
- pop ax
- jmp short nakout4 ; do next packet
-
- nakout3:mov dx,offset erms17 ; error exit, too many retries
- jmp giveup
-
- nakout4:inc al ; next sequence number
- and al,3fh
- cmp al,ah ; sent all packets?
- jne nakout1 ; ne = no, repeat more packets
- ret ; return to do another data send
- nakout endp
-
- cntretry proc near ; count retries, sense user exit
- cmp flags.cxzflg,'C' ; user wants abrupt exit?
- je cntre2 ; e = yes
- cmp flags.cxzflg,'E' ; Error type exit?
- je cntre2 ; e = yes
- inc fsta.pretry ; increment the number of retries
- inc [si].numtry ; for this packet too
- test flags.remflg,dserver ; server mode?
- jnz cntre3 ; nz = yes, writing to their screen
- cmp flags.xflg,1 ; writing to screen?
- je cntre1 ; e = yes, skip this
- cntre3: cmp fmtdsp,0 ; formatted display?
- je cntre1 ; e = no
- call rtmsg ; display retries
- cntre1: clc
- ret
- cntre2: mov sstate,'E' ; abort, shared by send and receive
- mov rstate,'E' ; abort
- stc
- ret
- cntretry endp
-
- ; Display message in ACK's to F and D packets. Requires a leading protocol
- ; char for D packets and expects message to be encoded.
- ackmsg proc near
- test flags.remflg,dquiet ; quiet display mode?
- jnz ackmsgx ; nz = yes, don't write to screen
- cmp rpacket.datlen,0 ; any embedded message?
- je ackmsgx ; e = no
- cmp sstate,'F' ; file header state?
- je ackmsg1 ; e = yes, no leading protocol char
- cmp rpacket.datlen,1 ; D packet, skip protocol char
- je ackmsgx ; e = no displayable information
- ackmsg1:push si
- push ax
- push dx
- call cxmsg ; clear message space in warning area
- mov word ptr decbuf,0 ; clear two bytes
- mov si,offset rpacket ; source address
- call dodec ; decode message, including X/Z/other
- mov dx,offset decbuf+1 ; decoded data
- cmp sstate,'F' ; file header state?
- jne ackmsg3 ; ne = no
- push dx
- mov dx,offset infms5 ; give a leader msg
- call prtasz
- pop dx
- dec dx ; start with first message char
- ackmsg2:mov bx,dx
- cmp byte ptr [bx],' ' ; space?
- jne ackmsg3 ; ne = no
- inc dx ; next msg char
- jmp short ackmsg2 ; continue stripping off spaces
- ackmsg3:call prtasz ; display message
- mov ah,prstr
- mov dx,offset crlf
- int dos
- pop dx
- pop ax
- pop si
- ackmsgx:mov rpacket.datlen,0
- ret
- ackmsg endp
-
- ; Shrink transmitted D packets by 1/2 to accomodate comms failures
- shrink proc near
- push ax
- mov ax,current_max ; current max packet length
- shr ax,1 ; divide by two
- cmp ax,40 ; too small?
- jae shrink1 ; ae = no
- mov ax,40 ; smallest size
- shrink1:mov current_max,ax ; new max packet length
- pop ax
- ret
- shrink endp
-
- ; Enlarge transmitted D packets by 5/4 to recover from comms failures
- grow proc near
- push ax
- mov ax,current_max ; current max packet length
- shr ax,1
- shr ax,1
- add ax,current_max ; 5/4 * current max
- cmp ax,trans.maxdat ; max negotiated
- jbe grow1 ; be = not exceeded
- mov ax,trans.maxdat ; limit to negotiated
- grow1: mov current_max,ax
- pop ax
- ret
- grow endp
-
- ; newfn -- move replacement name from buffer auxfile to buffer encbuf
-
- newfn proc near
- push si
- push di
- cmp auxfile,0 ; sending file under different name?
- je newfn4 ; e = no, so don't give new name
- mov si,offset auxfile ; source field
- mov di,offset fsta.xname ; statistics external name area
- call strcpy
- test flags.remflg,dquiet ; quiet display mode?
- jnz newfn2 ; nz = yes, do not write to screen
- mov dx,offset asmsg ; display ' as '
- cmp mailflg,0 ; mail?
- je newfn1 ; e = no
- mov dx,offset mailto ; display ' To: '
- newfn1: call prtasz ; display asciiz msg
- cmp mailflg,0 ; mail?
- je newfn2 ; e = no
- mov dx,offset auxfile ; get name
- call prtasz ; display asciiz string
- jmp short newfn4 ; don't replace filename
- newfn2: mov si,offset auxfile ; external name
- mov di,offset encbuf
- call strcpy ; put into encoder buffer
- test flags.remflg,dquiet ; quiet display mode (should we print)?
- jnz newfn5 ; nz = yes
- mov dx,si
- call prtasz ; display external name
- newfn4: test flags.remflg,dserial ; serial display mode?
- jz newfn5 ; z = no
- mov dx,offset crlf ; start with cr/lf for serial display
- mov ah,prstr
- int dos
- newfn5: pop di
- pop si
- ret
- newfn endp
-
- ; This routine sets up the data for the response to an Init packet
- ; trans.rxxx are items which have been negotiated.
- ; Lines marked ;M energize the second CAPAS byte. Leave them as comments
- ; because earlier versions of MS Kermit (and C Kermit) are confused by it
- ; (failed to decode bit saying second CAPAS byte follows and thus lose sync).
- ; Enter with SI = pktinfo pointer
- ; Returns [si].datlen = length of data field, with packet buffer filled in.
- RPAR PROC NEAR
- push ax
- push di
- push es
- cld
- les di,[si].datadr ; data field address to es:di
- mov al,trans.rpsiz ; receive packet size
- add al,' ' ; add a space to make it printable
- stosb ; 1, put it in the packet
- mov al,trans.rtime ; receive packet time out
- add al,' '
- stosb ; 2
- mov al,trans.rpad ; number of padding chars
- add al,' '
- stosb ; 3
- mov al,trans.rpadch ; padding char
- add al,40h ; Uncontrol it
- and al,7FH
- stosb ; 4
- mov al,trans.reol ; EOL char
- add al,' '
- stosb ; 5
- mov al,trans.rquote ; quote char
- stosb ; 6
- mov al,trans.ebquot ; 8-bit quote char
- stosb ; 7
- mov al,trans.chklen ; Length of checksum
- add al,'0' ; make into a real digit
- stosb ; 8
- mov al,trans.rptq ; repeat quote char
- or al,al ; null means none
- jnz rpar0
- mov al,' ' ; send a blank instead
- rpar0: stosb ; 9
- mov al,2 ; CAPAS, bit1 = can do long packets
- cmp flags.attflg,0 ; allowing attributes packets?
- je rpar1 ; e = no
- or al,8 ; bit #3, can do file attributes
- rpar1: or al,4 ; bit #4 can do windows
- cmp dtrans.lshift,lock_disable ; locking shift disabled?
- je rpar2 ; e = yes
- or al,20h ; set locking shift cap (bit #1)
- rpar2: add al,20h ; apply tochar() to byte
- ;M or al,1 ; say second CAPAS byte follows
- stosb ; 10
- ; additional CAPAS go in here
- ;M mov al,20h+20h ; Allow M (message) pkts, (#6, bit5)
- ;M stosb ; 11
- mov al,trans.windo ; number of active window slots (1-31)
- add al,20h ; apply tochar()
- stosb
- push dx ; save reg
- mov ax,trans.rlong ; longest packet which we can receive
- xor dx,dx ; clear extended part for division
- div ninefive ; divide by 95. quo = ax, rem = dx
- add al,20h ; apply tochar() to quotient
- stosb
- add dl,20h ; apply tochar() to remainder
- mov al,dl
- pop dx ; restore regs
- stosb
- sub di,word ptr [si].datadr ; end minus beginning = length
- mov [si].datlen,di ; length of rpar data in packet
- pop es
- pop di
- pop ax
- ret
- RPAR ENDP
-
- ; Set maximum capabilities
- ; dtrans are the defaults (which the user can modify), trans are negotiated
- ; and active values.
- SPARMAX PROC NEAR
- push ax
- mov al,dtrans.spsiz ; [1] regular packet size MAXL
- mov trans.spsiz,al
- mov al,dtrans.stime ; [2] send timeout value TIME
- mov trans.rtime,al
- mov al,dtrans.spad ; [3] send padding count NPAD
- mov trans.spad,al
- mov al,dtrans.spadch ; [4] send padding character PADC
- mov trans.spadch,al
- mov al,dtrans.seol ; [5] EOL character EOL
- mov trans.seol,al
- mov al,dtrans.squote ; [6] control quote character QCTL
- mov trans.squote,al
- push bx ; [7] 8-bit quote character QBIN
- mov bx,portval
- mov ah,[bx].parflg ; get our parity flag
- pop bx
- mov al,'Y' ; will quote upon request
- cmp dtrans.lshift,lock_force ; locking shift forced?
- jne spmax1 ; ne = no
- mov al,'N' ; ignore 8-bit quote
- jmp short spmax1a ; for any parity
- spmax1: cmp ah,parnon ; parity of none?
- je spmax1a ; e = yes, reset 8 bit quote character
- mov al,dqbin ; we want quoting, active
- spmax1a:mov trans.ebquot,al ; save quoting state
- mov dtrans.ebquot,al
- mov al,dtrans.chklen ; [8] initial checksum type CHKT
- mov trans.chklen,al
- mov al,dtrans.rptq ; [9] repeat prefix character REPT
- mov trans.rptq,al
- mov al,8+4 ; [10] capas bitmap CAPAS
- cmp dtrans.lshift,lock_disable ; locking shift disabled?
- je spmax2 ; e = yes
- or al,20h ; locking shift capa
- spmax2: mov trans.capas,al ; [10] capas bitmap CAPAS
- mov trans.capas+1,20h ; [11] CAPAS+1, Message pkts
- mov al,dtrans.windo ; [12] window size WINDO
- mov trans.windo,al
- mov ax,dtrans.slong ; [13-14] long packet send length,
- mov trans.slong,ax ; MAXLX1 and MAXLX2
- ;
- mov al,dtrans.rpsiz ; max regular packet we can receive
- mov trans.rpsiz,al ; for window of one slot
- mov ax,dtrans.rlong ; max long packet we can receive
- mov trans.rlong,ax ; for window of one slot
- pop ax
- ret
- SPARMAX ENDP
-
- ; This routine reads in all the send init packet information
- ; Enter with SI = pktinfo address, [si].datlen = packet length
- ; All regs preserved except AX.
- ; dtrans.xxx are the default parameters if the other side says nothing
- ; trans.sxxx are the active negotiated parameters we will use.
- SPAR PROC NEAR
- push es
- push ax ; set min defaults for no host data
- mov trans.spsiz,80 ; [1] regular packet size MAXL
- mov al,dtrans.stime ; get user selected stime
- mov trans.stime,al ; [2] send timeout value TIME
- mov trans.spad,0 ; [3] send padding count NPAD
- mov al,dtrans.spadch ; [4] send padding character PADC
- mov trans.spadch,al
- mov trans.seol,CR ; [5] EOL character EOL
- mov trans.squote,'#' ; [6] control quote character QCTL
- push bx ; [7] 8-bit quote character QBIN
- mov bx,portval ; current port settings
- mov ah,[bx].parflg ; get our parity flag
- pop bx
- mov al,'Y' ; say will quote upon request
- cmp dtrans.lshift,lock_force ; locking shift forced?
- jne spar0a ; ne = no
- mov al,'N' ; ignore 8-bit quotes
- jmp short spar0b ; regardless of parity
- spar0a: cmp ah,parnon ; parity of none?
- je spar0b ; e = yes
- mov al,dqbin ; we want quoting, active
- spar0b: mov trans.ebquot,al ; use proper quote char
- mov dtrans.ebquot,al
- mov trans.chklen,1 ; [8] initial checksum type CHKT
- xor ax,ax
- mov trans.rptq,al ; [9] repeat prefix character REPT
- mov trans.capas,al ; [10-11] capas bitmap CAPAS
- mov trans.capas+1,al
- mov trans.lshift,lock_disable ; init locking shift to disabled
- mov trans.windo,1 ; [12] window size WINDO
- mov al,trans.spsiz
- mov trans.slong,ax ; [13-14] long packet send length,
- ; MAXLX1 and MAXLX2
- ; start negotiations
- push si ; pktinfo structure pointer
- mov ax,[si].datlen ; length of received data
- mov ah,al ; number of args is now in ah
- les si,[si].datadr ; es:si is pointer to received data
- cld
- or ah,ah ; [1] MAXL any data?
- jg spar1a ; g = yes
- jmp sparx1
- spar1a: mov al,es:[si] ; get the max regular packet size
- inc si
- dec ah ; ah = bytes remaining to be examined
- sub al,' ' ; subtract ascii bias
- jnc spar1b ; c = old C Kermit error
- mov al,spmax
- spar1b: cmp al,dtrans.spsiz ; user limit is less?
- jbe spar1c ; be = no
- mov al,dtrans.spsiz ; replace with our lower limit
- spar1c: cmp al,spmin ; below the minimum?
- jge spar1d ; ge = no
- mov al,spmin
- spar1d: cmp al,spmax ; or above the maximum?
- jle spar1e ; le = no
- mov al,spmax
- spar1e: mov trans.spsiz,al ; save it
- push ax
- xor ah,ah ; set long packet to regular size
- mov trans.slong,ax
- pop ax
-
- or ah,ah ; [2] TIME more data?
- jg spar2a ; g = yes
- jmp sparx1
- spar2a: mov al,es:[si] ; get the timeout value
- inc si
- dec ah
- sub al,' ' ; subtract a space
- jge spar2b ; must be non-negative
- xor al,al ; negative, so use zero
- spar2b: cmp al,trans.rtime ; same as other side's timeout
- jne spar2c ; ne = no
- inc al ; yes, but make it a little different
- spar2c: cmp dtrans.stime,dstime ; is current value the default?
- je spar2d ; e = yes, else user value overrides
- mov al,dtrans.stime ; get user selected stime
- spar2d: mov trans.stime,al ; save it
- ;
- or ah,ah ; [3] NPAD more data?
- jg spar3a ; g = yes
- jmp sparx1
- spar3a: mov al,es:[si] ; get the number of padding chars
- inc si
- dec ah
- sub al,' '
- jge spar3b ; must be non-negative
- xor al,al
- spar3b: mov trans.spad,al ; number of padding chars to send
- ;
- or ah,ah ; [4] PADC more data?
- jg spar4a ; g = yes
- jmp sparx1
- spar4a: mov al,es:[si] ; get the padding char
- inc si
- dec ah
- add al,40h ; remove ascii bias
- and al,7FH
- cmp al,del ; Delete?
- je spar4b ; e = yes, then it's OK
- cmp al,31 ; control char?
- jbe spar4b ; be = yes, then OK
- xor al,al ; no, use null
- spar4b: mov trans.spadch,al
- ;
- or ah,ah ; [5] EOL more data?
- jg spar5a ; g = yes
- jmp sparx1
- spar5a: mov al,es:[si] ; get the EOL char
- inc si
- dec ah
- sub al,' '
- cmp al,31 ; control char?
- jbe spar5b ; le = yes, then use it
- mov al,cr ; else use the default
- spar5b: mov trans.seol,al ; EOL char to be used
- ;
- or ah,ah ; [6] QCTL more data?
- jg spar6a ; g = yes
- jmp sparx1
- spar6a: mov al,es:[si] ; get the quote char
- inc si
- dec ah
- cmp al,' ' ; less than a space?
- jge spar6b ; ge = no
- mov al,dsquot ; yes, use default
- spar6b: cmp al,7eh ; must also be less than a tilde
- jbe spar6c ; be = is ok
- mov al,dsquot ; else use default
- spar6c: mov trans.squote,al
- ;
- or ah,ah ; [7] QBIN more data?
- jg spar7a ; g = yes
- jmp sparx1
- spar7a: mov al,es:[si] ; get other side's 8-bit quote request
- inc si
- dec ah
- call doquo ; and set quote char
- ;
- or ah,ah ; [8] CHKT more data?
- jg spar8a ; a = yes
- jmp sparx1
- spar8a: mov al,es:[si] ; get other side's checksum length
- inc si
- dec ah
- call dochk ; determine what size to use
- ;
- or ah,ah ; [9] REPT more data?
- jg spar9a ; g = yes
- jmp sparx1
- spar9a: mov al,es:[si] ; get other side's repeat count prefix
- inc si
- dec ah
- call dorpt ; negotiate prefix into trans.rptq
- ;
- or ah,ah ; [10] CAPAS more data?
- ja spar10a ; g = yes
- jmp sparx1
- spar10a:mov al,es:[si] ; get CAPAS bitmap from other side
- inc si
- dec ah
- and al,not (1) ; remove least significant bit
- sub al,20h ; apply unchar()
- mov trans.capas,al ; store result in active byte
- test al,20h ; locking shift proposed?
- jz spar11 ; z = no
- cmp dtrans.lshift,lock_enable ; have we enabled its negotiation?
- jb spar11 ; b = no, (0) disabled
- ja spar10b ; a = (2) forced
- mov al,trans.ebquot ; get negotiated 8-bit quote char
- cmp al,'N' ; did 8-bit quote negotiation fail?
- je spar11 ; e = yes, no locking shift agreement
- cmp al,'Y' ; did 8-bit quote negotiation fail?
- je spar11 ; e = yes, no locking shift agreement
- mov trans.lshift,lock_enable ; set state of locking shift
- jmp short spar11
- spar10b:mov trans.ebquot,'N' ; ignore 8-bit quote prefix
- mov trans.lshift,lock_force ; and activate working copy
- spar11: or ah,ah ; [11] CAPAS+ more data?
- ja spar11a ; a = yes
- jmp sparx1
- spar11a:test byte ptr [si-1],1 ; is CAPAS byte continued to another?
- jz spar12 ; z = no
- mov al,es:[si] ; get 2nd CAPAS bitmap from other side
- inc si
- dec ah
- and al,not (1) ; remove least significant bit
- sub al,20h ; apply unchar(). Store nothing
- mov trans.capas+1,al ; keep second CAPAS byte
-
- spar11c:or ah,ah ; [11] CAPAS++ more data?
- ja spar11d ; a = yes
- jmp sparx1
- spar11d:test byte ptr es:[si-1],1 ; is CAPAS byte continued to another?
- jz spar12 ; z = no
- mov al,es:[si] ; 3rd et seq CAPAS bitmaps
- inc si
- dec ah
- and al,not (1) ; remove least significant bit
- sub al,20h ; apply unchar(). Store nothing
- jmp short spar11c ; seek more CAPAS bytes
- ;
- spar12: or ah,ah ; [12] WINDO more data?
- jg spar12a ; g = yes
- jmp sparx1 ; exit spar
- spar12a:mov al,es:[si] ; get other side's window size
- inc si
- dec ah
- sub al,20h ; apply unchar()
- call dewind ; negotiate window size
- ;
- cmp ah,2 ; [13-14] MAXL (long packet needs 2)
- jge spar13a ; ge = enough data to look at
- push ax ; make long same size as regular
- xor ah,ah
- mov al,trans.spsiz ; normal packet size
- mov trans.slong,ax ; assume not using long packets
- pop ax ; recover ah
- jmp short sparx1 ; do final checks on packet length
- spar13a:test trans.capas,2 ; do they have long packet capability?
- jnz spar13b ; nz = yes
- jmp short sparx1 ; no, skip following l-pkt len fields
- spar13b:mov al,es:[si] ; long pkt length, high order byte
- inc si
- push ax ; save ah
- sub al,20h ; apply unchar()
- xor ah,ah
- mul ninefive ; times 95 to dx (high), ax (low)
- mov trans.slong,ax ; store high order part
- mov al,es:[si] ; long pkt length, low order byte
- inc si
- sub al,20h ; apply unchar()
- xor ah,ah
- add ax,trans.slong ; plus high order part
- mov trans.slong,ax ; store it
- or ax,ax ; if result is 0 then use regular pkts
- jnz spar13c ; non-zero, use what they want
- mov al,trans.spsiz ; else default to regular packet size
- xor ah,ah
- mov trans.slong,ax ; and ignore the CAPAS bit (no def 500 bytes)
- spar13c:cmp ax,dtrans.slong ; longer than we want to do?
- jbe spar13d ; be = no
- mov ax,dtrans.slong ; limit to our longest sending size
- mov trans.slong,ax ; and use it
- spar13d:push dx
- mov dl,trans.spsiz ; regular pkt length
- xor dh,dh
- cmp ax,dx ; long pkt shorter than regular?
- jae spar13f ; ae = no
- cmp al,spmin ; below the minimum allowed length?
- jae spar13e ; ae = yes
- mov al,spmin ; drop down to minimum
- mov trans.slong,ax ; update long pkt too
- spar13e:mov trans.spsiz,al ; use small long packet length
- spar13f:pop dx
- pop ax ; recover ah
- ; Windowing can further shrink pkts
- sparx1: push cx ; final packet size negotiations
- push dx
- mov ax,maxbufparas ; our max buffer size, paragraphs
- mov cl,trans.windo ; number of active window slots
- xor ch,ch
- sub ax,cx ; minus null byte and rounding/slot
- jcxz sparx2 ; 0 means 1, for safety here
- xor dx,dx ; whole buffer / # window slots
- div cx ; ax = longest windowed pkt possible
- ; transmitter packet size
- sparx2: cmp ax,(9024/16) ; longest packet, in paragraphs
- jbe sparx2a ; be = less than eq longest
- mov ax,(9024/16)
- sparx2a:mov cl,4 ; convert to bytes
- shl ax,cl ; ax has bytes per buffer
- cmp ax,trans.slong ; our slots can be longer than theirs?
- ja sparx2b ; a = yes, use their shorter length
- mov trans.slong,ax ; no, use our shorter length
- sparx2b:mov cl,trans.spsiz ; current regular pkt size
- xor ch,ch
- cmp cx,ax ; is regular longer than window slot?
- jbe sparx3 ; be = no
- mov trans.spsiz,al ; shrink regular to windowed size
- ; receiver packet size
- sparx3: cmp ax,dtrans.rlong ; slot shorter than longest allowed?
- jae sparx5 ; ae = no
- mov trans.rlong,ax ; long size we want to receive
- mov cl,dtrans.rpsiz ; regular packet size user limit
- xor ch,ch
- cmp cx,ax ; is regular longer than window too?
- jbe sparx4 ; be = no
- mov cl,al ; shrink regular to windowed size
- sparx4: mov trans.rpsiz,cl ; regular size we want
- sparx5:
- push bx ; list of protected control codes
- xor bh,bh
- mov bl,flowon ; flow control
- or bl,bl ; any?
- jz sparx5a ; z = none
- and protlist[bx],not 1 ; if active
- mov bl,flowoff
- and protlist[bx],not 1
- sparx5a:cmp flags.comflg,'t' ; doing internal TCP?
- jne sparx6 ; ne = no
- mov protlist[127],0 ; protect DEL and IAC
- sparx6: pop bx
-
- pop dx
- pop cx
- pop si ; saved at start of spar
- pop ax
- pop es
- ret
- SPAR ENDP
-
- ; Set 8-bit quote character based on my capabilities and the other
- ; Kermit's request. Quote if one side says Y and the other a legal char
- ; or if both sides say the same legal char. Enter with AL = their quote char
- DOQUO PROC NEAR
- cmp dtrans.lshift,lock_force ; forcing locking shift?
- je dq3 ; e = yes, ignore 8-bit quoting
- cmp dtrans.ebquot,'N' ; we refuse to do 8-bit quoting?
- je dq3 ; e = yes, do not quote
- cmp al,'N' ; 'N' = they refuse quoting?
- je dq3 ; e = yes, do not quote
- cmp dtrans.ebquot,'Y' ; can we do it if requested?
- je dq2 ; e = yes, use their char in al
- cmp al,'Y' ; 'Y' = they can quote if req'd?
- jne dq1 ; ne = no, use their particular char
- mov al,dtrans.ebquot ; we want to use a particular char
- call prechk ; and they said 'Y', check ours
- jc dq3 ; c = ours is out of range, no quoting
- dq1: cmp al,dtrans.ebquot ; active quote vs ours, must match
- jne dq3 ; ne = mismatch, no quoting
- dq2: mov trans.ebquot,al ; get active char, ours or theirs
- cmp al,'Y'
- je dq4
- call prechk ; in range 33-62, 96-126?
- jc dq3 ; c = out of range, do not quote
- dq4: cmp al,trans.rquote ; same prefix as control-quote?
- je dq3 ; e = yes, don't do 8-bit quote
- cmp al,trans.squote ; same prefix control-quote?
- je dq3 ; this is illegal too
- mov trans.ebquot,al ; remember what we decided on
- ret
- dq3: mov trans.ebquot,'N' ; quoting will not be done
- ret
- DOQUO ENDP
-
- ; Check if prefix in AL is in the proper range: 33-62, 96-126.
- ; Return carry clear if in range, else return carry set.
- prechk: cmp al,33
- jb prechk2 ; b = out of range
- cmp al,62
- jbe prechk1 ; be = in range 33-62
- cmp al,96
- jb prechk2 ; b = out of range
- cmp al,126
- ja prechk2 ; a = out of range 96-126
- prechk1:clc ; carry clear for in range
- ret
- prechk2:stc ; carry set for out of range
- ret
-
- ; Set checksum length. AL holds their checksum request.
- dochk: cmp al,'1' ; Must be '1', '2', '3', or 'B'
- jb doc1 ; b = not '1' to '3'
- cmp al,'3'
- jbe doc2 ; be = ok
- cmp al,'B' ; special non-blank 2 byte?
- je doc2 ; e = yes
- doc1: mov al,'1' ; else use default of '1'
- doc2: sub al,'0' ; remove ascii bias
- mov trans.chklen,al ; other side's request is do-able here
- ret
-
- ; Set repeat count quote character. The one used must be different than
- ; the control and eight-bit quote characters. Also, both sides must
- ; use the same character
- dorpt: mov trans.rptq,0 ; assume will not repeat prefix
- call prechk ; is it in the valid range?
- jnc dorpt1 ; nc = in range
- xor al,al ; don't use their value
- dorpt1: cmp al,trans.squote ; same as the control quote char?
- je dorpt2 ; e = yes, that's illegal, no repeats
- cmp al,trans.rquote ; this too?
- je dorpt2 ; e = no good either
- cmp al,trans.ebquot ; same as eight bit quote char?
- je dorpt2 ; e = yes, illegal too, no repeats
- cmp al,dtrans.rptq ; both sides using same char?
- jne dorpt2 ; ne = no, that's no good either
- mov trans.rptq,al ; use repeat quote char now
- dorpt2: ret
-
- ; negotiate window size in al
- dewind: cmp al,dtrans.windo ; their (al) vs our max window size
- jbe dewind1 ; be = they want less than we can do
- mov al,dtrans.windo ; limit to our max size
- dewind1:or al,al
- jnz dewind2
- inc al ; use 1 if 0
- dewind2:mov trans.windo,al ; store active window size
- ret
-
-
- ; Set the maximum send data packet size; modified for long packets
- PACKLEN PROC NEAR
- push ax
- xor ah,ah
- mov al,trans.spsiz ; Maximum send packet size for Regular pkts.
- cmp ax,trans.slong ; negotiated long packet max size
- jae packle2 ; ae = use regular packets
- mov ax,trans.slong ; else use long kind
- sub ax,3 ; minus extended count & checksum
- cmp ax,(95*94-1-2) ; longer than Long?
- jle packle2 ; le = no, Long will do
- dec ax ; minus one more for extra long count
- packle2:sub ax,2 ; minus Sequence, Type
- cmp trans.chklen,'B'-'0' ; special 'B'?
- jne packle3 ; ne = no
- sub al,2 ; 'B' is two byte kind
- jmp short packle3a
- packle3:sub al,trans.chklen ; and minus Checksum chars
- packle3a:sbb ah,0 ; borrow propagate
- cmp trans.ebquot,'N' ; doing 8-bit Quoting?
- je packle0 ; e = no, so we've got our size
- cmp trans.ebquot,'Y'
- je packle0 ; e = not doing it in this case either
- dec ax ; another 1 for 8th-bit Quoting.
- packle0:cmp trans.rptq,0 ; doing repeat character Quoting?
- je packle1 ; e = no, so that's all for now
- dec ax ; minus repeat prefix
- dec ax ; and repeat count
- packle1:dec ax ; for last char might being a control code
- mov trans.maxdat,ax ; save max length for data field
- pop ax
- ret
- PACKLEN ENDP
-
- ; Print the number in AX on the screen in decimal rather that hex
-
- NOUT PROC NEAR
- test flags.remflg,dserver ; server mode?
- jnz nout2 ; nz = yes, writing to their screen
- cmp flags.xflg,0 ; receiving to screen?
- jne nout1 ; ne = yes
- nout2: test flags.remflg,dserial ; serial display mode?
- jnz pnout ; nz = use "dot and plus" for serial mode
- test flags.remflg,dquiet ; quiet display mode?
- jnz nout1 ; nz = yes. Don't write to screen
- call decout ; call standard decimal output routine
- nout1: ret
-
- pnout: or ax,ax ; display packet in serial display mode
- jz pnoutx ; z = nothing to display
- push ax ; for serial mode display
- push cx
- push dx ; output .........+.........+ etc
- xor dx,dx ; extended numerator
- mov cx,10
- div cx ; number/10. (AX=quo, DX=rem)
- or dx,dx ; remainder non-zero?
- jnz pnout1 ; nz = yes
- mov dl,'+' ; symbol plus for tens
- jmp short pnout2 ; display it
- pnout1: mov dl,'.' ; symbol for between tens
- pnout2: mov ah,conout ; output to console
- int dos
- pop dx
- pop cx
- pop ax
- pnoutx: ret
- NOUT ENDP
-
- ; Decode and display Error packet message.
- ERROR PROC NEAR
- mov sstate,'A' ; Set the state to abort
- push si
- mov si,offset rpacket ; source address
- call dodec ; decode to decbuf
- mov dx,offset decbuf ; where msg got decoded, asciiz
- call ermsg ; display string
- pop si
- stc ; set carry for failure state
- ret
- ERROR ENDP
-
- ; General routine for sending an error packet. Register BX should
- ; point to the text of the message being sent in the packet
-
- ERRPACK PROC NEAR
- push cx
- push di
- mov di,offset encbuf ; Where to put the message
- xor cx,cx
- errpa1: mov al,[bx]
- inc bx
- cmp al,'$' ; at end of message?
- je errpa2 ; e = terminator
- or al,al ; this kind of terminator too?
- jz errpa2 ; z = terminator
- inc cx ; count number of chars in msg
- mov [di],al ; copy message
- inc di
- jmp short errpa1
- errpa2: push si
- mov si,offset rpacket ; use response buffer
- mov al,pktnum
- mov rpacket.seqnum,al
- call doenc
- call pktsize ; report packet size
- mov rpacket.pktype,'E' ; send an error packet
- call spack
- mov rpacket.datlen,0 ; clear response buffer
- pop si
- pop di
- pop cx
- ret
- ERRPACK ENDP
-
- ; Enter with dx pointing to asciiz error message to be sent
- giveup proc near
- call bufclr ; release all buffers
- call ermsg ; position cursor, display asciiz msg
- mov bx,dx
- call errpack ; send error packet
- xor ax,ax
- mov auxfile,al ; clear send-as/mail-to buffer
- mov mailflg,al ; clear Mail flag
- cmp filopn,al ; disk files open?
- je giveu2 ; e = no so don't do a close
- mov ah,close2 ; close file
- push bx
- mov bx,diskio.handle ; file handle
- int dos
- pop bx
- mov filopn,0 ; say file is closed now
- giveu2: mov sstate,'A' ; abort state
- or errlev,kssend ; set DOS error level
- or fsta.xstatus,kssend ; set status
- mov kstatus,kssend ; global status
- stc ; set carry for failure status
- ret
- giveup endp
-
- code ends
- end
-